import {self} from "../dhtml-weixin/index"
function RGBEToLinear(r, g, b, a, color) {
  if (a === 0) {
    color[0] = color[1] = color[2] = 0;
    color[3] = 1;
  } else {
    var scale = Math.pow(2, a - 128) / 255;
    color[0] = r * scale;
    color[1] = g * scale;
    color[2] = b * scale;
    color[3] = 1;
  }
}
function RGBMToLinear(r, g, b, a, color) {
  var scale = a / 13005; // (a * 5) / 255 / 255;
  color[0] = r * scale;
  color[1] = g * scale;
  color[2] = b * scale;
  color[3] = 1;
}
function gammaToLinearSpace(value) {
  // https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_framebuffer_sRGB.txt
  // https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_sRGB_decode.txt
  if (value <= 0.0) return 0.0;else if (value <= 0.04045) return value / 12.92;else if (value < 1.0) return Math.pow((value + 0.055) / 1.055, 2.4);else return Math.pow(value, 2.4);
}
function addSH(direction, color, deltaSolidAngle, sh) {
  var x = direction[0];
  var y = direction[1];
  var z = direction[2];
  var r = color[0] * deltaSolidAngle;
  var g = color[1] * deltaSolidAngle;
  var b = color[2] * deltaSolidAngle;
  var bv0 = 0.282095; // basis0 = 0.886227
  var bv1 = -0.488603 * y; // basis1 = -0.488603
  var bv2 = 0.488603 * z; // basis2 = 0.488603
  var bv3 = -0.488603 * x; // basis3 = -0.488603
  var bv4 = 1.092548 * (x * y); // basis4 = 1.092548
  var bv5 = -1.092548 * (y * z); // basis5 = -1.092548
  var bv6 = 0.315392 * (3 * z * z - 1); // basis6 = 0.315392
  var bv7 = -1.092548 * (x * z); // basis7 = -1.092548
  var bv8 = 0.546274 * (x * x - y * y); // basis8 = 0.546274
  sh[0] += r * bv0, sh[1] += g * bv0, sh[2] += b * bv0;
  sh[3] += r * bv1, sh[4] += g * bv1, sh[5] += b * bv1;
  sh[6] += r * bv2, sh[7] += g * bv2, sh[8] += b * bv2;
  sh[9] += r * bv3, sh[10] += g * bv3, sh[11] += b * bv3;
  sh[12] += r * bv4, sh[13] += g * bv4, sh[14] += b * bv4;
  sh[15] += r * bv5, sh[16] += g * bv5, sh[17] += b * bv5;
  sh[18] += r * bv6, sh[19] += g * bv6, sh[20] += b * bv6;
  sh[21] += r * bv7, sh[22] += g * bv7, sh[23] += b * bv7;
  sh[24] += r * bv8, sh[25] += g * bv8, sh[26] += b * bv8;
}
function scaleSH(array, scale) {
  var src = array;
  src[0] *= scale, src[1] *= scale, src[2] *= scale;
  src[3] *= scale, src[4] *= scale, src[5] *= scale;
  src[6] *= scale, src[7] *= scale, src[8] *= scale;
  src[9] *= scale, src[10] *= scale, src[11] *= scale;
  src[12] *= scale, src[13] *= scale, src[14] *= scale;
  src[15] *= scale, src[16] *= scale, src[17] *= scale;
  src[18] *= scale, src[19] *= scale, src[20] *= scale;
  src[21] *= scale, src[22] *= scale, src[23] *= scale;
  src[24] *= scale, src[25] *= scale, src[26] *= scale;
}
function decodeFaceSH(faceData, faceIndex, decodeMode, textureSize, lastSolidAngleSum, sh // length 27
) {
  var channelLength = 4;
  var texelSize = 2 / textureSize; // convolution is in the space of [-1, 1]
  var color = [];
  var direction = [];
  var v = texelSize * 0.5 - 1;
  var solidAngleSum = lastSolidAngleSum;
  for (var y = 0; y < textureSize; y++) {
    var u = texelSize * 0.5 - 1;
    for (var x = 0; x < textureSize; x++) {
      var dataOffset = y * textureSize * channelLength + x * channelLength;
      switch (decodeMode) {
        case 0:
          color[0] = faceData[dataOffset];
          color[1] = faceData[dataOffset + 1];
          color[2] = faceData[dataOffset + 2];
          color[3] = 0;
          break;
        case 1:
          color[0] = gammaToLinearSpace(faceData[dataOffset] / 255);
          color[1] = gammaToLinearSpace(faceData[dataOffset + 1] / 255);
          color[2] = gammaToLinearSpace(faceData[dataOffset + 2] / 255);
          color[3] = 0;
          break;
        case 2:
          RGBEToLinear(faceData[dataOffset], faceData[dataOffset + 1], faceData[dataOffset + 2], faceData[dataOffset + 3], color);
          break;
        case 3:
          RGBMToLinear(faceData[dataOffset], faceData[dataOffset + 1], faceData[dataOffset + 2], faceData[dataOffset + 3], color);
          break;
      }
      switch (faceIndex) {
        case 0:
          direction[0] = 1;
          direction[1] = -v;
          direction[2] = -u;
          break;
        case 1:
          direction[0] = -1;
          direction[1] = -v;
          direction[2] = u;
          break;
        case 2:
          direction[0] = u;
          direction[1] = 1;
          direction[2] = v;
          break;
        case 3:
          direction[0] = u;
          direction[1] = -1;
          direction[2] = -v;
          break;
        case 4:
          direction[0] = u;
          direction[1] = -v;
          direction[2] = 1;
          break;
        case 5:
          direction[0] = -u;
          direction[1] = -v;
          direction[2] = -1;
          break;
      }
      /**
      * dA = cos = S / r = 4 / r
      * dw = dA / r2 = 4 / r / r2
      */
      var lengthSquared = direction[0] * direction[0] + direction[1] * direction[1] + direction[2] * direction[2];
      var directionLength = Math.sqrt(lengthSquared);
      var solidAngle = 4 / (directionLength * lengthSquared);
      // normalize
      direction[0] /= directionLength;
      direction[1] /= directionLength;
      direction[2] /= directionLength;
      solidAngleSum += solidAngle;
      addSH(direction, color, solidAngle, sh);
      u += texelSize;
    }
    v += texelSize;
  }
  return solidAngleSum;
}
      
  self.onmessage = function onmessage(event) {
    var data = event.data;
    var type = data.type,
      taskID = data.taskID;
    switch (type) {
      case "calculateSHFromTextureCube":
        var decodeMode = data.decodeMode,
          textureSize = data.textureSize,
          dataPX = data.dataPX,
          dataNX = data.dataNX,
          dataPY = data.dataPY,
          dataNY = data.dataNY,
          dataPZ = data.dataPZ,
          dataNZ = data.dataNZ;
        var sh = new Float32Array(27);
        var solidAngleSum = 0;
        solidAngleSum = decodeFaceSH(dataPX, 0, decodeMode, textureSize, solidAngleSum, sh);
        solidAngleSum = decodeFaceSH(dataNX, 1, decodeMode, textureSize, solidAngleSum, sh);
        solidAngleSum = decodeFaceSH(dataPY, 2, decodeMode, textureSize, solidAngleSum, sh);
        solidAngleSum = decodeFaceSH(dataNY, 3, decodeMode, textureSize, solidAngleSum, sh);
        solidAngleSum = decodeFaceSH(dataPZ, 4, decodeMode, textureSize, solidAngleSum, sh);
        solidAngleSum = decodeFaceSH(dataNZ, 5, decodeMode, textureSize, solidAngleSum, sh);
        scaleSH(sh, 4 * Math.PI / solidAngleSum);
        self.postMessage({
          type: "calculateSHFromTextureCube",
          taskID: taskID,
          result: sh
        });
        break;
    }
  };
